package com.tmanager.utils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.Charset;
import java.security.MessageDigest;

/**
 * @author Paul A. Shmarev
 */
public class Crypto {
    public static final Charset UTF8 = Charset.forName("UTF-8");
    private static final char[] HEX = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    private static final String ALGORITHM = "DES";
    private static final String TRANSFORMATION = "DES/ECB/PKCS5Padding";


    public static String digestSHA1(String str) {
        byte[] digest;
        try {
            MessageDigest sha1;
            sha1 = MessageDigest.getInstance("SHA1");
            sha1.update(str.getBytes("UTF-8"));
            digest = sha1.digest();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return bytesToHex(digest);
    }

    public static String encodeBase64(byte[] bytes) {
        return DatatypeConverter.printBase64Binary(bytes);
    }

    public static byte[] decodeBase64(String str) {
        return DatatypeConverter.parseBase64Binary(str);
    }

    public static String bytesToHex(byte[] bytes) {
        int i = 0;
        char[] chars = new char[2 * bytes.length];
        for (byte b : bytes) {
            int high = ((b & 0xf0) >> 4);
            chars[i++] = HEX[high];
            int low = (b & 0x0f);
            chars[i++] = HEX[low];
        }
        return String.valueOf(chars);
    }

    public static byte[] hexToBytes(char[] hex) {
        int length = hex.length / 2;
        byte[] raw = new byte[length];
        for (int i = 0; i < length; i++) {
            int high = Character.digit(hex[i * 2], 16);
            int low = Character.digit(hex[i * 2 + 1], 16);
            int value = (high << 4) | low;
            if (value > 127)
                value -= 256;
            raw[i] = (byte) value;
        }
        return raw;
    }

    public static byte[] hexToBytes(String hex) {
        return hexToBytes(hex.toCharArray());
    }

    public static byte[] encryptDES(SecretKey key, byte[] bytes) {
        try {
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] decryptDES(SecretKey key, byte[] bytes) {
        try {
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return cipher.doFinal(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static SecretKey generateDESKey(String keyPhrase) {
        byte keyBytes[] = new byte[8];
        byte[] keyPhraseBytes = keyPhrase.getBytes(UTF8);
        int len = keyPhraseBytes.length;
        if (keyPhrase.length() >= 8) {
            for (int i = 0; i < len; i++) {
                keyBytes[i % 8] ^= keyPhraseBytes[i];
            }
        } else {
            for (int i = 0; i < 8; i++) {
                keyBytes[i] = keyPhraseBytes[i % len];
            }
        }
        try {
            DESKeySpec keySpec = new DESKeySpec(keyBytes);
            return SecretKeyFactory.getInstance(ALGORITHM).generateSecret(keySpec);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
